SPDX-FileCopyrightText: 2021 Gaston Demoulin & Loïc Mabire SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be
SPDX-License-Identifier: GPL-3.0-or-later
Music in similar motion - Philip Glass 1969 # # final script- 25/01/2020 - Loïc M - Gaston D # Blender 2.93.4 #
import bpy
import random
import bmesh
import mathdef clean(): # cleanup fonction
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)
bpy.ops.outliner.orphans_purge()def curve(measure, coords):
curveData = bpy.data.curves.new(measure, type="CURVE")
curveData.dimensions = "3D"
curveData.resolution_u = 20
polyline = curveData.splines.new("NURBS")
polyline.points.add(len(coords) - 1)
for i, coord in enumerate(coords):
x, y, z = coord
polyline.points[i].co = (x, y, z, 1)
curveOB = bpy.data.objects.new("mesure", curveData)
curveData.extrude = 0.1
myCollection = bpy.context.collection
myCollection.objects.link(curveOB)
bpy.data.scenes[0].collection.objects.link(curveOB)
return curveOBdef cube(position, echelle):
bpy.ops.mesh.primitive_cube_add(
size=1, enter_editmode=False, location=position, scale=echelle
)
bpy.ops.context.renamedef get_objects(name):
res = []
for obj in bpy.data.objects:
if name in obj.name:
res.append(obj)
return resdef dot():
print("-----")
print("-----")
clean()innit variable
listeZ = [-1, 1] # possibilities on z
listeX = [2, 3, 4] # possibilities on x
newco = []
sizex = 1
nbrepet = 0
nbadd = 0
list = [1, 0, 0, 0, 0, 0]
startInstrument = [0]
list_EP = []
facteur_EP = []
offsetrandom = []
ibis = -1
addX = 0
addX2 = 0strat by writing the first measure as coordinates
coord_list = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[random.choice(listeX), 0, random.choice(listeX)],
] # the first measure always start at 0,0,0
for i in range(0, 1):
coord_list.append(
[
coord_list[3 + i][0] + random.choice(listeX),
0,
coord_list[3 + i][2] + random.choice(listeZ),
]
)
for coordfin in range(0, 2):
coord_list.append(coord_list[-1])
coord_list_bis = coord_list
coord_list_prec = coord_listchoice start instrument
nbinstrument = random.randint(3, 5)
if nbinstrument >= 4:
var = 1.5
else:
var = 2.5
for a in range(0, nbinstrument):
facteur_EP.append(var * random.uniform(0.75, 1.25))
offsetrandom.append(random.uniform(-0.2, 0.2))
print("start intrumentbis")
print(nbinstrument)
print(startInstrument)strat writing for console reading
dot()
print("start")
dot() curve #
main loop writing the 14 measure of the piece as an evolutive coord_list
for i in range(
0, 14
): # all the rules writing the curves are stats from the original pieceeach new coord is added randomly within the actual list at ‘index’, keeping the first and last coords the same
index = random.randint(3, len(coord_list) - 4) # choose one coordinate in the list
prevx, prevy, prevz = coord_list[index] # read the coordinate at index14% chance of adding 0 coordinate, 50% of adding one, 36% of adding 2
resultchoice = random.randint(1, 100) # get the % for coord choicereset variables
addX = 0
addX2 = 0
choice0 = False
choice3 = Falseconsole reading
dot()
print("iteration", i + 1)
print("coord_liststart", coord_list)
print("index choosed", index, ":", coord_list[index])
if resultchoice <= 14: # 14% - add 0 coordinate
print("add 0")
nbadd = 0
choice0 = True
elif resultchoice <= 64: # 50% - add 1 coordinate
print("add 1")
nbadd = 2with the index coordinate we find the next one within the 6 possibilities:
addX = random.choice(listeX)
newX = prevx + addX
newZ = prevz + random.choice(listeZ)doing it twice
if (
newZ < -2
or coord_list[index - 2][2]
> coord_list[index - 1][2]
> coord_list[index][2]
):
newZ = newZ + 1
elif (
newZ > 4
or coord_list[index - 2][2]
< coord_list[index - 1][2]
< coord_list[index][2]
):
newZ = newZ - 1
else: # 36% - add 2 coordinate
print("add 2")
choice3 = True
nbadd = 3with the index coordinate we find the next one within the 6 possibilities:
addX = random.choice(listeX)
newX = prevx + addX
newZ = prevz + random.choice(listeZ)bounding box
if (
newZ < -2
or coord_list[index - 2][2]
> coord_list[index - 1][2]
> coord_list[index][2]
):
newZ = newZ + 1
elif (
newZ > 4
or coord_list[index - 2][2]
< coord_list[index - 1][2]
< coord_list[index][2]
):
newZ = newZ - 1doing it twice
addX2 = random.choice(listeX)
newX2 = newX + addX
newZ2 = newZ + random.choice(listeZ)bounding box
if (
newZ < -2
or coord_list[index - 2][2]
> coord_list[index - 1][2]
> coord_list[index][2]
):
newZ = newZ + 1
elif (
newZ > 4
or coord_list[index - 2][2]
< coord_list[index - 1][2]
< coord_list[index][2]
):
newZ = newZ - 1one in 5 chance to delete the first note of the measure
if 9 > len(coord_list) > 13:
chancesuppr = [1, 2, 3, 4, 5]
resultatsuprr = random.choice(chancesuppr)
if resultatsuppr == 3:
print("SUPPR", coord_list[4, 5])
del coord_list[4, 5]
coord_list_prec = coord_listinsert the new coordinate Xn1 after the Xn choosen
if choice0 == False: # newco = coordlist[index] if choice 0
newco = [newX, 0, newZ]
coord_list.insert(index + 1, newco)
print("newco ", newco)
if choice3 == True:
newco2 = [newX2, 0, newZ2]
coord_list.insert(index + 2, newco2)
print("newco2", newco2)move the coordinate after the Xn choosen on X by choice 0,1 or 2
for coord in coord_list[index + nbadd :]:
if i == 0:
coord[0] = coord[0] + (addX + addX2) / 3
else:
coord[0] = coord[0] + addX + addX2
print(addX + addX2)
dot()
print("coord_list", coord_list)
print("nombrecoo", len(coord_list))
dot()
print("00000")adding space
nbcoo = len(coord_list)
for l in range(0, nbcoo):
xbisH, ybisH, zbisH = coord_list[l]
del coord_list[l]
zbisH = zbisH + 1.45 # space between repetition
coord_list.insert(l, [xbisH, ybisH, zbisH])repetition courbe bis
nbrepet = random.randint(3, 10)
for k in range(0, nbrepet):
for voixa in range(0, nbinstrument):
if random.randint(0, 60) == 60:
list[voixa] = 1
if i >= 13:
list[voixa] = 1 extrusion #
for k in range(0, nbrepet):move up every repetition
for j in range(0, nbcoo):
xbis, ybis, zbis = coord_list[j]
del coord_list[j]
zbis = zbis + 0.5
coobis = [xbis, ybis, zbis]
coord_list_bis.insert(j, coobis)
for voix in range(0, nbinstrument):thickness and offset variable to always have 10cm lenght
if voix == nbinstrument - 1:
offset = -1
elif voix == 0:
offset = 1
else:
offset = 0 + offsetrandom[voix]
if list[voix] == 1:
maCourbeCreeBis = curve("mesurebis", coord_list_bis)
maCourbeCreeBis.select_set(True) # selection
sizex = 10 / coord_list[-1][0] # resize for curves = 10cm
bpy.ops.transform.resize(value=(sizex, 1, 1))
bpy.context.view_layer.objects.active = (
maCourbeCreeBis # 'maCourbeCreeBis' is the active object now
)
bpy.ops.object.modifier_add(type="SOLIDIFY")
bpy.context.object.modifiers["Solidify"].thickness = facteur_EP[
voix
] # facteur_EP #list_facteur(ii)
bpy.context.object.modifiers["Solidify"].offset = offset
bpy.ops.transform.translate(
value=(0, (10 / (nbinstrument - 1)) * voix, 0)
)
maCourbeCreeBis.select_set(False)
if k == (nbrepet - 3) and voix == 0: # signal
maCourbeCreeBis.select_set(True)
bpy.context.view_layer.objects.active = maCourbeCreeBis
bpy.ops.object.modifier_add(type="SOLIDIFY")
bpy.context.object.modifiers["Solidify"].thickness = (
10 # extrusion of the signal
)
bpy.context.object.modifiers["Solidify"].offset = 1
maCourbeCreeBis.select_set(False)
print(list)
ibis += 1
i += 1 pillars #
x, y, max_ztotal = max(coord_list_bis, key=lambda item: item[2])
tailleRectx = 0.2
tailleRecty = 0.1
for cix in range(0, 4):
if cix == 0:
ix = 1
elif cix == 3:
ix = 9
else:
ix = (10 / 3.5) * cix + 1
for ciy in range(1, 6):
if ciy == 1:
iy = 1
elif ciy == 5:
iy = 9
else:
iy = (10 / 5) * ciy - 1
cube(
(ix + tailleRectx / 2, iy, max_ztotal / 2),
(tailleRectx, tailleRecty, max_ztotal),
)Ext = maCourbeCreeBis # la tour
hauteur_cadrage = random.uniform(
5, (max_ztotal - 5)
) # pos z of the extraction of the towerdef boolean(mod, object):
bpy.ops.object.modifier_add(type="BOOLEAN")
bpy.context.object.modifiers["Boolean"].operation = "INTERSECT"
bpy.context.object.modifiers["Boolean"].solver = mod
bpy.context.object.modifiers["Boolean"].object = objectjoin everything in one MESH
bpy.ops.object.select_all(action="SELECT")
bpy.context.view_layer.objects.active = maCourbeCreeBis
bpy.ops.object.convert(target="MESH")
bpy.ops.object.join()
bpy.context.active_object.name = "Ext"Cadrage 1 : first cut
cube((5, 5, hauteur_cadrage), (12, 12, 10))
cube1 = get_objects("Cube")[0]
boolean("FAST", Ext)Cadrage 2 : Cube more précise but solver = FAST
cube((5, 5, hauteur_cadrage), (10.2, 10.2, 10))
cube2 = get_objects("Cube.001")[0]
boolean("FAST", cube1)
bpy.ops.object.modifier_apply(modifier="Boolean")Cadrage 3 : solver = EXACT
cube((5, 5, hauteur_cadrage), (10.2, 10.2, 10))
boolean("EXACT", cube2)on applique la fonction boolean cette fois seulement
bpy.ops.object.modifier_apply(modifier="Boolean")replace the cube at 0;0
bpy.ops.transform.translate(value=(0, 0, -hauteur_cadrage + 5))
bpy.ops.object.select_all(action="DESELECT")cleanup
cube1.select_set(True)
bpy.ops.object.delete(use_global=False)
cube2.select_set(True)
bpy.ops.object.delete(use_global=False)
tour = get_objects("Ext")[0]
tour.select_set(True)
bpy.ops.transform.translate(value=(20, 0, 0))closing volumes
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.editmode_toggle()bpy.ops.mesh.edge_face_add()
bpy.ops.mesh.normals_make_consistent(inside=True)
bpy.ops.mesh.remove_doubles(threshold=0.001)
bpy.ops.mesh.select_all(action="DESELECT")
bpy.ops.object.editmode_toggle()